package com.starry.module.system.core.dict.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.starry.core.common.constants.CommonError;
import com.starry.core.common.domain.vo.PageVo;
import com.starry.core.common.execption.ServiceException;
import com.starry.core.redis.service.RedisService;
import com.starry.db.core.enums.DBEnableDisableStatusEnum;
import com.starry.db.core.query.LambdaQueryWrapperX;
import com.starry.module.system.api.dict.domain.qo.SysDictionaryDataPageQo;
import com.starry.module.system.api.dict.domain.qo.SysDictionaryDataQo;
import com.starry.module.system.api.dict.domain.vo.SysDictionaryDataDtlVo;
import com.starry.module.system.api.dict.domain.vo.SysDictionaryDataVo;
import com.starry.module.system.core.dict.entity.SysDictionaryData;
import com.starry.module.system.core.dict.mapper.SysDictionaryDataMapper;
import com.starry.module.system.core.dict.service.SysDictionaryDataService;
import com.starry.module.system.core.redis.RedisKeyConstants;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * 系统字典内容-服务实现
 *
 * @author xiaoke
 */
@Service("sysDictionaryDataService")
public class SysDictionaryDataServiceImpl implements SysDictionaryDataService {

    private final SysDictionaryDataMapper sysDictionaryDataMapper;
    private final RedisService redisService;

    public SysDictionaryDataServiceImpl(SysDictionaryDataMapper sysDictionaryDataMapper, RedisService redisService) {
        this.sysDictionaryDataMapper = sysDictionaryDataMapper;
        this.redisService = redisService;
    }

    @Override
    public PageVo<SysDictionaryDataVo> page(SysDictionaryDataPageQo pageQo) {
        PageVo<SysDictionaryData> page = sysDictionaryDataMapper.selectPage(pageQo);
        List<SysDictionaryDataVo> vos = BeanUtil.copyToList(page.getRows(), SysDictionaryDataVo.class);
        return new PageVo<>(vos, page.getTotal());
    }

    @Override
    public List<SysDictionaryDataVo> getByDictType(String dictType) {
        String key = RedisKeyConstants.SYS_DICTIONARY_DETAILS + dictType;
        List<SysDictionaryDataVo> list = redisService.getCacheList(key);
        if (!list.isEmpty()) {
            return list;
        }
        List<SysDictionaryData> sysDictionaryData = sysDictionaryDataMapper.selectByDictType(dictType);
        if (sysDictionaryData.isEmpty()) {
            return Collections.emptyList();
        }
        list = BeanUtil.copyToList(sysDictionaryData, SysDictionaryDataVo.class);
        redisService.setCacheList(key, list, 2, TimeUnit.DAYS);
        return list;
    }

    @Override
    public SysDictionaryDataDtlVo getById(Long id) {
        SysDictionaryData sysDictionaryData = sysDictionaryDataMapper.selectById(id);
        if (sysDictionaryData == null) {
            throw new ServiceException(CommonError.DATA_NOT_EXISTS.getMsg());
        }
        return BeanUtil.toBean(sysDictionaryData, SysDictionaryDataDtlVo.class);
    }

    @Transactional
    @Override
    public Long save(SysDictionaryDataQo sysDictionaryDataQo) {
        LambdaQueryWrapperX<SysDictionaryData> wrapper = new LambdaQueryWrapperX<>();
        wrapper
                .eq(SysDictionaryData::getDictType, sysDictionaryDataQo.getDictType())
                .eq(SysDictionaryData::getName, sysDictionaryDataQo.getName());
        if (sysDictionaryDataMapper.selectCount(wrapper) > 0) {
            throw new ServiceException(CommonError.DATA_EXISTS.getMsg());
        }
        SysDictionaryData sysDictionaryData = BeanUtil.toBean(sysDictionaryDataQo, SysDictionaryData.class);
        sysDictionaryData.setId(null);
        sysDictionaryDataMapper.insert(sysDictionaryData);
        return sysDictionaryData.getId();
    }

    @Transactional
    @Override
    public void updateById(SysDictionaryDataQo sysDictionaryDataQo) {
        if (sysDictionaryDataQo.getId() == null) {
            throw new ServiceException(CommonError.DATA_NOT_EXISTS.getMsg());
        }
        LambdaQueryWrapperX<SysDictionaryData> wrapper = new LambdaQueryWrapperX<>();
        wrapper
                .ne(SysDictionaryData::getId, sysDictionaryDataQo.getId())
                .and(w ->
                        w.eq(SysDictionaryData::getName, sysDictionaryDataQo.getName())
                                .eq(SysDictionaryData::getDictType, sysDictionaryDataQo.getDictType())
                );
        if (sysDictionaryDataMapper.selectCount(wrapper) > 0) {
            throw new ServiceException(CommonError.DATA_EXISTS.getMsg());
        }
        SysDictionaryData sysDictionaryData = sysDictionaryDataMapper.selectById(sysDictionaryDataQo.getId());
        if (sysDictionaryData == null) {
            throw new ServiceException(CommonError.DATA_NOT_EXISTS.getMsg());
        }
        BeanUtil.copyProperties(sysDictionaryDataQo, sysDictionaryData);
        sysDictionaryDataMapper.updateById(sysDictionaryData);

        // 删除缓存
        deleteDetailCache(sysDictionaryData.getDictType());
    }

    @Transactional
    @Override
    public void removeByIds(Set<Long> idList) {
        if (idList.isEmpty()) return;
        sysDictionaryDataMapper.deleteByIds(idList);

        // 删除缓存
        deleteDetailCache(idList);
    }

    @Transactional
    @Override
    public void enable(Set<Long> idList) {
        if (idList.isEmpty()) return;
        sysDictionaryDataMapper.updateBatch(setDictionaryDataStatus(idList, DBEnableDisableStatusEnum.ENABLE));

        // 删除缓存
        deleteDetailCache(idList);
    }

    @Transactional
    @Override
    public void disable(Set<Long> idList) {
        if (idList.isEmpty()) return;
        sysDictionaryDataMapper.updateBatch(setDictionaryDataStatus(idList, DBEnableDisableStatusEnum.DISABLE));

        // 删除缓存
        deleteDetailCache(idList);
    }

    @Override
    public void deleteDetailCache(String dictType) {
        redisService.deleteObject(RedisKeyConstants.SYS_DICTIONARY_DETAILS + dictType);
    }

    /**
     * 删除列表缓存
     *
     * @param idList id列表
     */
    private void deleteDetailCache(Set<Long> idList) {
        if (idList.isEmpty()) return;
        List<SysDictionaryData> sysDictionaryDatas = sysDictionaryDataMapper.selectList(SysDictionaryData::getId, idList);
        sysDictionaryDatas.forEach(item -> {
            deleteDetailCache(item.getDictType());
        });
    }

    private Set<SysDictionaryData> setDictionaryDataStatus(Set<Long> idList, DBEnableDisableStatusEnum status) {
        Set<SysDictionaryData> sysDictionaryDatas = new HashSet<>();
        idList.forEach(item -> {
            SysDictionaryData sysDictionaryData = new SysDictionaryData();
            sysDictionaryData.setId(item);
            sysDictionaryData.setStatus(status.getCode());
            sysDictionaryDatas.add(sysDictionaryData);
        });
        return sysDictionaryDatas;
    }


}

